#include "xlcomm/net/http/http_server.h"

#include "xlcomm/net/http/http_context.h"

namespace xlcomm {
namespace net {

void DefaultHttpCallback(const HttpRequest&, HttpResponse* resp) {
  LOG_DEBUG << __FUNCTION__ << "---- do nothing.";
  resp->set_status_code(HttpResponse::k404NotFound);
  resp->set_close_connection(true);
}

HttpServer::HttpServer(EventLoop* loop, const InetAddress& listen_add)
    : loop_(loop),
      server_(loop, listen_add, "HttpServer"),
      http_request_cb_(std::bind(DefaultHttpCallback, _1, _2)) {
  server_.set_connect_callback(std::bind(&HttpServer::OnConnect, this, _1));
  server_.set_message_callback(
      std::bind(&HttpServer::OnMessage, this, _1, _2, _3));
}

void HttpServer::OnConnect(const TcpConnectionPtr& conn) {
  conn->set_context(HttpContext());
}

void HttpServer::OnMessage(const TcpConnectionPtr& conn, Buffer* buff,
                           Timestamp recv_time) {
  LOG_TRACE << "----";
  HttpContext* context =
      boost::any_cast<HttpContext>(conn->GetMutableContext());

  if (!context->ReadToRequest(buff)) {
    conn->Send("HTTP/1.1 400 Bad Request\r\n\r\n");
    conn->Shutdown();
    return;
  }

  if (context->GotAll()) {
    OnRequest(conn, context->request());
    context->Reset();
  }
}

void HttpServer::OnRequest(const TcpConnectionPtr& conn,
                           const HttpRequest& req) {
  HttpResponse resp;
  if (http_request_cb_) {
    http_request_cb_(req, &resp);
  }
  const std::string& connection = req.GetHeader("Connection");
  bool close = connection == "close" || (req.version_ == HttpRequest::kHttp10 &&
                                         connection != "Keep-Alive");
  resp.set_close_connection(close);
  conn->Send(resp.ToString());
  if (close) conn->Shutdown();
}

}  // namespace net
}  // namespace xlcomm